package com.company.eos.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.company.eos.common.util.RandomUtil;
import com.company.eos.common.util.RedisUtil;
import com.company.eos.exception.EmosException;
import com.company.eos.mapper.AuditMeetingMapper;
import com.company.eos.domain.AuditMeeting;
import com.company.eos.service.AuditDetailService;
import com.company.eos.service.AuditFlowService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.company.eos.common.util.PageUtils;
import com.company.eos.service.AuditMeetingService;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author: Song, Wei
 * @date: 2022-03-03
 */
@Service
@Slf4j
public class AuditMeetingServiceImpl extends ServiceImpl<AuditMeetingMapper, AuditMeeting>
        implements AuditMeetingService {

    @Autowired
    private AuditMeetingMapper auditMeetingMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private AuditDetailService auditDetailService;
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 查询线下会议分页表单
     *
     * @param param 分页查询的请求参数
     * @return 分页对象
     */
    @Override
    public PageUtils searchOfflineMeetingByPage(HashMap param) {
        ArrayList<HashMap> list = auditMeetingMapper.searchOfflineMeetingByPage(param);
        long count = auditMeetingMapper.searchOfflineMeetingCount(param);
        // int start = (int) param.get("start");
        int start = MapUtil.getInt(param, "start");
        int length = MapUtil.getInt(param, "length");
        // 把meeting字段转换成JSON数组对象
        for (HashMap map : list) {
            String meeting = (String) map.get("meeting");
            // 如果Meeting是有效的字符串，就转换成JSON数组对象
            if (meeting != null && meeting.length() > 0) {
                map.replace("meeting", JSONUtil.parseArray(meeting));
            }
        }
        PageUtils pageUtils = new PageUtils(list, count, start, length);
        return pageUtils;
    }

    /**
     * 查询线上会议分页
     *
     * @param param 分页查询的参数
     * @return 分页对象
     */
    @Override
    public PageUtils searchOnlineMeetingByPage(HashMap param) {
        ArrayList<HashMap> list = auditMeetingMapper.searchOnlineMeetingByPage(param);
        Long count = auditMeetingMapper.searchOnlineMeetingCount(param);
        int start = (Integer) param.get("start");
        int length = (Integer) param.get("length");
        return new PageUtils(list, count, start, length);
    }

    /**
     * 新增会议申请
     *
     * @param auditMeeting 会议对象
     * @return 新增行数
     */
    @Override
    public int insert(AuditMeeting auditMeeting) {
        // 备注：审批工作流程中的会议申请已经添加
        int row = auditMeetingMapper.insert(auditMeeting);
        if (row != 1) {
            throw new EmosException("会议添加失败");
        }
        return row;
    }

    /**
     * 查询线下会议周日历
     *
     * @param param 查询周日历的参数
     * @return 列表
     */
    @Override
    public ArrayList<HashMap> searchOfflineMeetingInWeek(HashMap param) {
        return auditMeetingMapper.searchOfflineMeetingInWeek(param);
    }

    /**
     * 查询线下会议详情
     *
     * @param status 状态
     * @param id     ID
     * @return HashMap对象
     */
    @Override
    public HashMap searchMeetingInfo(int status, int id) {
        // 判断正在进行中的会议
        HashMap map;
        // 正在进行和已经结束的会议都可以查询present和unpresent字段
        if (status == 4 || status == 5) {
            map = auditMeetingMapper.searchCurrentMeetingInfo(id);
        } else {
            map = auditMeetingMapper.searchMeetingInfo(id);
        }
        return map;
    }

    /**
     * 删除会议
     *
     * @param param 删除会议传输的参数
     * @return 删除的数量
     */
    @Override
    public int deleteMeetingApplication(HashMap param) {
        Integer flowId = MapUtil.getInt(param, "flowId");

        // 查询会议详情，判断是否距离会议开始不足20分钟
        HashMap meeting = auditMeetingMapper.searchMeetingById(param);
        // 获取会议开始时间和结束时间和状态
        String date = MapUtil.getStr(meeting, "date");
        String start = MapUtil.getStr(meeting, "start");
        int status = MapUtil.getInt(meeting, "status");
        boolean isCreator = Boolean.parseBoolean(MapUtil.getStr(meeting, "isCreator"));

        DateTime dateTime = DateUtil.parse(date + " " + start);
        DateTime now = DateUtil.date();

        // 只能申请人删除该会议
        if (!isCreator) {
            throw new EmosException("只能申请人删除该会议");
        }

        // 待审批和未开始已结束的会议可以删除
        if (status == 1 || status == 3 || status == 5) {
            int rows = auditMeetingMapper.deleteMeetingApplication(param);
            if (rows == 1) {
                // 删除会议申请，删除审批流程表中的会议申请记录
                auditDetailService.deleteAudit(flowId);
            }
            return rows;
        } else {
            //距离会议开始不足20分钟，不能删除会议
            if (now.isAfterOrEquals(dateTime.offset(DateField.MINUTE, -20))) {
                throw new EmosException("距离会议开始不足20分钟，不能删除会议");
            }
            throw new EmosException("只能删除待审批和未开始的会议");
        }


    }

    /**
     * 查询视频会议RoomId
     *
     * @param uuid 会议对应的 UUID
     * @return 线上会议的房间ID
     */
    @Override
    public Long searchRoomIdByUuid(String uuid) {
        if (redisTemplate.hasKey(uuid)) {
            final Object temp = redisTemplate.opsForValue().get(uuid);
            return Long.parseLong(temp.toString());
        }
        return null;
    }

    /**
     * 查询线上会议成员
     *
     * @param param 线上会议查询的参数
     * @return 线上会议的成员
     */
    @Override
    public ArrayList<HashMap> searchOnlineMeetingMembers(HashMap param) {
        return auditMeetingMapper.searchOnlineMeetingMembers(param);
    }

    /**
     * 查询会议是否可以签到
     *
     * @param param 查询参数
     * @return 是否可以签到
     */
    @Override
    public boolean searchCanCheckMeeting(HashMap param) {
        final Long count = auditMeetingMapper.searchCanCheckMeeting(param);
        return count == 1;
    }

    /**
     * 更新出席人员名单
     *
     * @param param 更新的参数
     * @return 更新的数量
     */
    @Override
    public int updateMeetingPresent(HashMap param) {
        return auditMeetingMapper.updateMeetingPresent(param);
    }

    /**
     * 请求时更新线下会议的状态，保证用户接触到的会议的状态为最新
     */
    @Override
    public void updateOfflineMeetingStatus() {
        List<AuditMeeting> auditMeetings = auditMeetingMapper.selectList(Wrappers.lambdaQuery(AuditMeeting.class)
                // 1在线会议，2线下会议
                .eq(AuditMeeting::getType, 2)
                // 3表示已经审核通过，4表示正在进行中
                .in(AuditMeeting::getStatus, 3, 4));
        for (AuditMeeting auditMeeting : auditMeetings) {
            // 判断会议的开始时间是否早于当前
            Date date = auditMeeting.getDate();     // 只存储了日期
            Date start = auditMeeting.getStart();   // 只存储了时间
            Date end = auditMeeting.getEnd();       // 只存储了时间
            SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");
            String startTimeStr = sdfDate.format(date) + " " + sdfTime.format(start);
            String endTimeStr = sdfDate.format(date) + " " + sdfTime.format(end);
            DateTime startTime = DateTime.of(startTimeStr, "yyyy-MM-dd HH:mm:ss");
            DateTime endTime = DateTime.of(endTimeStr, "yyyy-MM-dd HH:mm:ss");
            long startTimeLong = startTime.getTime();
            long endTimeLong = endTime.getTime();
            long nowTimeLong = new Date().getTime();
            if (startTimeLong < nowTimeLong && nowTimeLong < endTimeLong) {
                // 进行中
                auditMeeting.setStatus(4);
            } else if (endTimeLong < nowTimeLong) {
                // 已结束
                auditMeeting.setStatus(5);
            }
            // 更新会议状态
            auditMeetingMapper.update(auditMeeting, Wrappers.lambdaQuery(AuditMeeting.class)
                    .eq(AuditMeeting::getId, auditMeeting.getId()));
        }
    }

    /**
     * 查询请求时更新线上会议的状态，保证用户接触到的会议的状态为最新
     */
    @Override
    public void updateOnlineMeetingStatus() {
        List<AuditMeeting> auditMeetings = auditMeetingMapper.selectList(Wrappers.lambdaQuery(AuditMeeting.class)
                // 1在线会议，2线下会议
                .eq(AuditMeeting::getType, 1)
                // 3表示已经审核通过，4表示正在进行中
                .in(AuditMeeting::getStatus, 3, 4));
        for (AuditMeeting auditMeeting : auditMeetings) {
            // 判断会议的开始时间是否早于当前
            Date date = auditMeeting.getDate();     // 只存储了日期
            Date start = auditMeeting.getStart();   // 只存储了时间
            Date end = auditMeeting.getEnd();       // 只存储了时间
            SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");
            String startTimeStr = sdfDate.format(date) + " " + sdfTime.format(start);
            String endTimeStr = sdfDate.format(date) + " " + sdfTime.format(end);
            DateTime startTime = DateTime.of(startTimeStr, "yyyy-MM-dd HH:mm:ss");
            DateTime endTime = DateTime.of(endTimeStr, "yyyy-MM-dd HH:mm:ss");
            long startTimeLong = startTime.getTime();
            long endTimeLong = endTime.getTime();
            long nowTimeLong = new Date().getTime();
            // 判断当前状态是审批通过还是正在进行
            if (auditMeeting.getStatus() == 3) {
                // 判断是否正在进行
                if (startTimeLong < nowTimeLong && nowTimeLong < endTimeLong) {
                    // 进行中
                    auditMeeting.setStatus(4);
                }
                // 因为线上会议设置了可以提前十分钟进场，所以判断是否正在进行中，可以根据这个进行设置
                // 现在时间在开始时间前面10分钟，就生成会议室ID
                if (startTimeLong - nowTimeLong <= 10 * 60 * 1000) {
                    // 若为正在进行，则需要生成会议的RoomId；考虑到会议可能延长，适当增加两个小时
                    redisUtil.setIfAbsent(auditMeeting.getUuid(), RandomUtil.randomNumber(8),
                            endTimeLong - startTimeLong + 120 * 60 * 1000, TimeUnit.MILLISECONDS);
                }
            } else if (auditMeeting.getStatus() == 4) {
                // 正在进行，判断是否已经结束
                if (endTimeLong < nowTimeLong) {
                    // 已结束，结束时间早于当前时间
                    auditMeeting.setStatus(5);
                }
            }
            // 更新会议状态
            auditMeetingMapper.update(auditMeeting, Wrappers.lambdaQuery(AuditMeeting.class)
                    .eq(AuditMeeting::getId, auditMeeting.getId()));
        }
    }
}
